// Fill out your copyright notice in the Description page of Project Settings.

#include "Isalong2.h"
#include "UIManager.h"

AUIManager* AUIManager::_UIManager = nullptr;


void AUIManager::BeginProgress(float time)
{
	_progressTarget = time;
	_progressTimer = 0;
}

void AUIManager::InterruptProgress()
{
	FinishProgress();
}

void AUIManager::FinishProgress()
{
	_progressTarget = -1;
	_progressTimer = 0;
	GlobalData::Init()->Str_Set<float>(PLAYER_UIRING, 0);
	OnProgressedCallBack.Clear();
}

void AUIManager::TickProgress(float DeltaTime)
{
	if (_progressTarget<0)
	{
		return;
	}
	_progressTimer += DeltaTime;
	GlobalData::Init()->Str_Set<float>(PLAYER_UIRING, _progressTimer / _progressTarget);
	if (_progressTimer>_progressTarget)
	{
		// call delegate
		OnProgressedCallBack.Broadcast();
		FinishProgress();
	}
}

void AUIManager::OnDataChange(string key)
{
	if (key==PLAYER_UIMIDNOTIFY)
	{
		_notify->OnNotifyMiddle(FString(GlobalData::Init()->Str_Get<string>(PLAYER_UIMIDNOTIFY).c_str()), GlobalData::Init()->Str_Get<float>(PLAYER_UIMIDNOTIFYADDITION));
	}
	if (key==PLAYER_UIRING)
	{
		_notify->OnRingPercentChange(GlobalData::Init()->Str_Get<float>(PLAYER_UIRING));
	}
	if (key==PLAYER_FOOD)
	{
		_notify->OnHungryChange(GlobalData::Init()->Str_Get<int>(PLAYER_FOOD));
	}
	if (key==PLAYER_HEALTH)
	{
		_notify->OnHealthChange(GlobalData::Init()->Str_Get<int>(PLAYER_HEALTH));
	}
	if (key==PLAYER_WATER)
	{
		_notify->OnWaterChange(GlobalData::Init()->Str_Get<int>(PLAYER_WATER));
	}
	if (key == PLAYER_IMMUNITY)
	{
		_notify->OnImmunityChange(GlobalData::Init()->Str_Get<int>(PLAYER_IMMUNITY));
	}
	if (key==PLAYER_BAGCURRENT||key==PLAYER_BAGTOTAL)
	{
		_notify->OnBagLeftChange(GlobalData::Init()->Str_Get<float>(PLAYER_BAGCURRENT), GlobalData::Init()->Str_Get<float>(PLAYER_BAGTOTAL));
	}
}

void AUIManager::SetWeaponBoxMode(int32 mode)
{
	if (_notify!=nullptr)
	{
		_notify->SetRightDownMode(mode);
		return;
	}
	_oldRequestMode.Add(mode);
}

void AUIManager::AddItemNotify(int32 id, int32 count)
{
	_notify->OnItemAddNotify(id, count);
}

void AUIManager::UpdateWeaponBox(int32 theLeft, int32 theRight)
{
	if (_notify!=nullptr)
	{
		_notify->OnRightDownUpdate(theLeft, theRight);
		return;
	}
	_oldUpdateRequest.Add(theLeft);
	_oldUpdateRequest.Add(theRight);
}

void AUIManager::AddDisplayItemIcon(IDisplayHUDItem* item)
{
	if (!_displayingArray.Contains(item)) { _displayingArray.Add(item); }
}

void AUIManager::RemoveDisplayItemIcon(IDisplayHUDItem* item)
{
	if (_displayingArray.Contains(item)) { _displayingArray.Remove(item); }
}

void AUIManager::AddDisplayBlood(AActor* owner, bool useTimer, float maxTime /*= 0*/, float bloodVal /*= 0.5*/)
{
	for (int i=0;i<_displayBlood.Num();i++)
	{
		if (_displayBlood[i]._owner==owner)
		{
			_displayBlood[i]._bloodVal = bloodVal;
			_displayBlood[i]._maxTime = maxTime;
			_displayBlood[i]._useTimer = useTimer;
			_displayBlood[i]._showTime = 0;
			return;
		}
	}
	_displayBlood.Add(FBloodDisplayBlock(owner, useTimer, maxTime, bloodVal));
}

void AUIManager::UpdateDisplayBlood(AActor* owner, float newVal)
{
	for (int i = 0; i < _displayBlood.Num(); i++)
	{
		if (_displayBlood[i]._owner == owner)
		{
			_displayBlood[i]._bloodVal = newVal;
			return;
		}
	}
}

void AUIManager::RemoveDisplayBlood(AActor* owner)
{
	for (int i=0;i<_displayBlood.Num();i++)
	{
		if (_displayBlood[i]._owner==owner)
		{
			_displayBlood.RemoveAt(i);
			return;
		}
	}
}

void AUIManager::ShowInventoryUI()
{
	_inventoryUI->OnInventoryShow();
}

void AUIManager::HideInventoryUI()
{
	_inventoryUI->OnInventoryHide();
}

void AUIManager::ShowRingSelector()
{
	_ringUI->OnShowSelectorRing();
}

void AUIManager::HideRingSelector()
{
	_ringUI->OnHideSelectorRing();
}

AUIManager::AUIManager()
{
	// sig
	ACGameManager::_gameManager->WriteLine("Init UI Manager");
	AUIManager::_UIManager = this;
	// other usually not here for construct twice
}

void AUIManager::Tick(float DeltaSeconds)
{
	// maintain the blood display list
	for (int i=0;i<_displayBlood.Num();i++)
	{
		if (_displayBlood[i]._useTimer)
		{
			_displayBlood[i]._showTime += DeltaSeconds;
			if (_displayBlood[i]._showTime>=_displayBlood[i]._maxTime)
			{
				_displayBlood.RemoveAt(i);
				i--;
			}
		}
	}
	// tick progress
	TickProgress(DeltaSeconds);
}

void AUIManager::BeginPlay()
{
	// setup UI
	GlobalData::Init()->Str_Bind<string>(PLAYER_UIMIDNOTIFY, this);
	GlobalData::Init()->Str_Bind<float>(PLAYER_UIRING, this);
	GlobalData::Init()->Str_Bind<int>(PLAYER_HEALTH, this);
	GlobalData::Init()->Str_Bind<int>(PLAYER_FOOD, this);
	GlobalData::Init()->Str_Bind<int>(PLAYER_WATER, this);
	GlobalData::Init()->Str_Bind<int>(PLAYER_IMMUNITY, this);
	GlobalData::Init()->Str_Bind<float>(PLAYER_BAGTOTAL, this);
	GlobalData::Init()->Str_Bind<float>(PLAYER_BAGCURRENT, this);

	_notify = CreateWidget<UNotifyUI>(ACPlayerCharacterController::_localPlayerController, ACIsAlongGameMode::_isAlongGameMode->_notifyClass);
	_notify->AddToViewport();

	_inventoryUI = CreateWidget<UMainInventoryUI>(ACPlayerCharacterController::_localPlayerController, ACIsAlongGameMode::_isAlongGameMode->_mainInventoryClass);
	_inventoryUI->AddToViewport();

	_ringUI = CreateWidget<UToolSelectorUI>(ACPlayerCharacterController::_localPlayerController, ACIsAlongGameMode::_isAlongGameMode->_ringSelectorClass);
	_ringUI->AddToViewport();
	
	if (_oldRequestMode.Num()!=0)
	{
		SetWeaponBoxMode(_oldRequestMode[_oldRequestMode.Num() - 1]);
		_oldRequestMode.Empty();
	}
	if (_oldUpdateRequest.Num()!=0)
	{
		UpdateWeaponBox(_oldUpdateRequest[_oldUpdateRequest.Num() - 2], _oldUpdateRequest[_oldUpdateRequest.Num() - 1]);
		_oldUpdateRequest.Empty();
	}
}

void AUIManager::DrawHUD()
{
	// cal the project matrix
	FVector2D viewportSize(1, 1);
	UWorld* World = GEngine->GetWorldFromContextObject(this);
	if (World && World->IsGameWorld())
	{
		if (UGameViewportClient* ViewportClient = World->GetGameViewport())
		{
			ViewportClient->GetViewportSize(viewportSize);
		}
	}
	FVector2D ScreenPosition;
	FSceneViewProjectionData ProjectionData;
	ULocalPlayer* const LP = ACPlayerCharacterController::_localPlayerController->GetLocalPlayer();
	LP->GetProjectionData(LP->ViewportClient->Viewport, eSSP_FULL, /*out*/ ProjectionData);
	FMatrix const ViewProjectionMatrix = ProjectionData.ComputeViewProjectionMatrix();
	FVector displayPosition;

	// do the display array display the Texture
	for (int i = 0; i < _displayingArray.Num(); i++)
	{
		UTexture2D* displayTexture = _displayingArray[i]->GetDisplayItemIcon();
		displayPosition = _displayingArray[i]->GetDisplayItemWorldPosition();
		if (displayTexture != nullptr)
		{
			ScreenPosition = FVector2D::ZeroVector;
			FSceneView::ProjectWorldToScreen(displayPosition, ProjectionData.GetConstrainedViewRect(), ViewProjectionMatrix, ScreenPosition);
			if (ScreenPosition.X == 0 && ScreenPosition.Y == 0)
				continue;
			
			float imageScale = 0.1;
			float floatingHeightScale = 0.13;
			DrawTextureSimple(displayTexture, ScreenPosition.X - imageScale*displayTexture->GetSizeX() / 2, ScreenPosition.Y -viewportSize.Y*floatingHeightScale- imageScale*displayTexture->GetSizeY() / 2,imageScale,false);
		}
	}

	// do the blood display
	for (int i=0;i<_displayBlood.Num();i++)
	{
		if (!_displayBlood[i]._owner->IsValidLowLevel())
		{
			_displayBlood.RemoveAt(i);
			i--;
			continue;
		}
		float displayScale = 0.25;
		ACGameManager::_gameManager->WriteScreen(0, "Draw");
		ScreenPosition = FVector2D::ZeroVector;
		displayPosition = _displayBlood[i]._owner->GetActorLocation();
		FSceneView::ProjectWorldToScreen(displayPosition, ProjectionData.GetConstrainedViewRect(), ViewProjectionMatrix, ScreenPosition);
		if (ScreenPosition.X == 0 && ScreenPosition.Y == 0)
			continue;
		UTexture2D* border = ResourceManager::_resourceManager->_bloodBarBorder;
		UTexture2D* body = ResourceManager::_resourceManager->_bloodBarContain;
		DrawTextureSimple(ResourceManager::_resourceManager->_bloodBarBorder, ScreenPosition.X -displayScale* border->GetSizeX() / 2, ScreenPosition.Y -displayScale* border->GetSizeY() / 2,displayScale);
		DrawTexture(body, ScreenPosition.X -displayScale* body->GetSizeX() / 2, ScreenPosition.Y -displayScale* body->GetSizeY() / 2,displayScale* body->GetSizeX()*(_displayBlood[i]._bloodVal<0?0.0001:_displayBlood[i]._bloodVal),displayScale* body->GetSizeY(), 0, 0, 1, 1);
	}
}
